/*
alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Microsoft Excel oversized ib memory corruption attempt"; flowbits:isset,file.xls; flow:to_client,established; content:"|16 00 02 00|"; content:"|17 00|"; distance:2; within:2; content:"|06 00|"; metadata:policy balanced-ips drop, policy security-ips drop, service http; classtype:attempted-user; reference:cve,2009-3131; reference:url,technet.microsoft.com/en-us/security/bulletin/MS09-067; sid:16230;)
*/
/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif


/* declare detection functions */
int rule16230eval(void *p);

/* declare rule data structures */
/* precompile the stuff that needs pre-compiled */
/* flowbits:isset "file.xls"; */
static FlowBitsInfo rule16230flowbits0 =
{
    "file.xls",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule16230option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule16230flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule16230flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule16230option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule16230flow1
    }
};
#ifndef CONTENT_FAST_PATTERN
#define CONTENT_FAST_PATTERN 0
#endif
// content:"|16 00 02 00|", depth 0, fast_pattern; 
static ContentInfo rule16230content2 = 
{
    (uint8_t *) "|16 00 02 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16230option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16230content2
    }
};
// content:"|17 00|", offset 2, depth 2, relative; 
static ContentInfo rule16230content3 = 
{
    (uint8_t *) "|17 00|", /* pattern (now in snort content format) */
    2, /* depth */
    2, /* offset */
    CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16230option3 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16230content3
    }
};
// content:"|06 00|", depth 0; 
static ContentInfo rule16230content4 = 
{
    (uint8_t *) "|06 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_NORMALIZED|CONTENT_RELATIVE, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16230option4 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16230content4
    }
};

/* references for sid 16230 */
/* reference: cve "2009-3131"; */
static RuleReference rule16230ref1 = 
{
    "cve", /* type */
    "2009-3131" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/MS09-067"; */
static RuleReference rule16230ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/MS09-067" /* value */
};

static RuleReference *rule16230refs[] =
{
    &rule16230ref1,
    &rule16230ref2,
    NULL
};
/* metadata for sid 16230 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule16230service1 = 
{
    "service http"
};


//static RuleMetaData rule16230policy1 = 
//{
//    "policy balanced-ips drop"
//};
//
//static RuleMetaData rule16230policy2 = 
//{
//    "policy security-ips drop"
//};


static RuleMetaData *rule16230metadata[] =
{
    &rule16230service1,
//    &rule16230policy1,
//    &rule16230policy2,
    NULL
};

RuleOption *rule16230options[] =
{
    &rule16230option0,
    &rule16230option1,
    &rule16230option2,
    &rule16230option3,
    &rule16230option4,
    NULL
};

Rule rule16230 = {
   
   /* rule header, akin to => tcp any any -> any any               */{
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       16230, /* sigid */
       9, /* revision */
   
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-OFFICE Microsoft Excel oversized ib memory corruption attempt",     /* message */
       rule16230refs /* ptr to references */
       ,rule16230metadata
   },
   rule16230options, /* ptr to rule options */
   &rule16230eval, /* use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule16230eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *beg_of_payload, *end_of_payload;
    uint16_t arraycount;
    uint16_t /*sb,*/ ib;

    DEBUG_SO(printf("rule16230eval enter\n"));

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flowbits:isset "file.xls";
    if (processFlowbits(p, rule16230options[0]->option_u.flowBit) > 0) {
            // flow:established, to_client;
        if (checkFlow(p, rule16230options[1]->option_u.flowFlags) > 0 ) {
            // content:"|16 00 02 00|", depth 0, fast_pattern;
            if (contentMatch(p, rule16230options[2]->option_u.content, &cursor_normal) > 0) {
                // content:"|17 00|", offset 2, depth 2, relative;
                if (contentMatch(p, rule16230options[3]->option_u.content, &cursor_normal) > 0) {
                    DEBUG_SO(printf("found |17 00|\n"));

                    //Nab the cxals, the array size value
                    arraycount = read_little_16(cursor_normal-4); 

                    DEBUG_SO(printf("arraycount=0x%04x\n", arraycount));

                    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                        return RULE_NOMATCH;

                    // content:"|06 00|", depth 0;
                    while (contentMatch(p, rule16230options[4]->option_u.content, &cursor_normal) > 0) {
                        DEBUG_SO(printf("found |06 00|\n"));

                        if (cursor_normal + 28 > end_of_payload)
                            return RULE_NOMATCH;

                        //Check the first RPN type in the RPN array and see if it is a type between
                        //0x39 and 0x3d. Types can actually be found throughout the array, but we're
                        //limiting detection to just the first byte in each RPN array per formula
                        //record. This is because inspecting the entire array would require 
                        //a complete templating out of each type with an inherent knowledge of the
                        //size of data to follow each type specifier as well as have extra performance
                        //considerations. There is no other way to know where in the array to expect
                        //the next 'type' byte except by knowing beforehand how much data comes after
                        //each type.
                        if (*(cursor_normal+24) >= 0x39 && *(cursor_normal+24) <= 0x3d) {
                            
                            //Extract the two shorts after the type specifier
                            ib = read_little_16(cursor_normal+25);

                            DEBUG_SO(printf("ib = 0x%04x\n", ib));

                            // We're ignoring the sb value because the GUT code from Microsoft
                            // is different than what the guidance says.  The GUT code seems
                            // to just check if they need to make ib positive.  We read ib as
                            // unsigned so we'll just leave it be.
                            
                            //sb = *(cursor_normal+27);
                            //sb |= *(cursor_normal+28) << 8;

                            //If sb is non-zero, negate the first value
                            //We know this makes no sense, but it's what the guidance says
                            //if (*(cursor_normal+27) || *(cursor_normal+28))
                            //    ib = -ib;

                            DEBUG_SO(printf("alert if ib=%d > arraycount=%d\n", ib, arraycount));

                            //Compare first short with array counter from earlier.
                            //If higher, then fire.
                            if (ib > arraycount)
                                return RULE_MATCH;
                        }

                    }
                }
            }
        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule16230,
    NULL
};
*/

